
import DataManger from './datamanger.js'
import displayMng from './display.js'
import { CoordTRFUtil } from './common/tools/coordtool.js'
import LXCOM from './common/common.js'
import {InitGraphObjSvc} from './service/initobjsvc.js'
import editINTF from './interface/editINTF.js'
import shortcutkeysvc from './service/shortcutkeysvc.js'
import getdataINTF from './interface/getdataINTF.js'
import datasaveINTF from './interface/datasaveINTF.js'
import symbolINTF from './interface/symbolINTF.js'
import eventclassifysvc from './eventclassifysvc.js'
import copypastesvc from './service/copypastesvc.js'
import rectselectsvc from './service/rectselectsvc.js'
import dragdropsvc from './service/dragdropsvc.js'
import animateintf from './interface/animateINTF.js'
import configINTF from './interface/configINTF.js'
import RMenuINTF from './interface/RMenuINTF.js'
import layerINTF from './interface/layerINTF.js'
import dynamicINTF from './interface/dynamicINTF.js'
import { UniversalINTF } from './interface/universalINTF.js'

import { LGXMatrix } from './common/struct/math/matrix.js'

import { LGXEnums } from './common/sysenum.js'

import { SelectAllSvc } from './service/selectallsvc.js'
import { MainControllerFactory } from './controler/maincontrollerfactory.js'
import graphdatafactory from '../manage/graphdatafactory.js'
import utilfuncs from './common/tools/utilfuncs.js'
var funcs = utilfuncs.UtilFuncs;

import globalConst from './common/globalConst.js'
var global = globalConst.GlobalConst;

class MapCanvas {
    constructor(canvas, map, mapwid, maphgt, worldMapRect, editMode) {
        this.painter = map;
        this.canvas = canvas;
        this.name = 'default';
        this.editMode = editMode;
        this.dataManger = new DataManger.DataManger(mapwid, maphgt, worldMapRect, editMode);
        this.m_pRectSelectService = new rectselectsvc.RectSelectSvc(this.dataManger);
        this.displayMng = new displayMng.DisplayMng(mapwid, maphgt);

        this.mainControler = MainControllerFactory.create(editMode, this.dataManger, this.displayMng, this.m_pRectSelectService);
        if (editMode == "xmind") {
            this.mainControler.autoCreateTrunckThemeGraph(map);
        }

        this.m_pEditINTF = new editINTF.EditINTF(this);
        this.m_pGetDataINTF = new getdataINTF.GetDataINTF(this);
        this.m_pDataSavaINTF = new datasaveINTF.DataSaveINTF(this);
        this.m_pSymbolINTF = new symbolINTF.SymbolINTF(this);
        this.m_pAnimateINTF = new animateintf.AnimateINTF(this);
        this.m_pConfigINTF = new configINTF.ConfigINTF(this);
        this.m_pRMenuINTF = new RMenuINTF.RMenuINTF(this);
        this.m_pLayerINTF = new layerINTF.LayerINTF(this);
        this.m_dynamicINTF = new dynamicINTF.DynamicINTF(this);
        this.m_universalINTF = new UniversalINTF(this);

        this.forbidMouseMove = false;
        this.m_eventListnerList = new Array();
        this.m_selGraphListnerList = new Array();
        this.m_preMouseScrnPt = new LXCOM.LGXPoint();
        this.m_preMouseWorldPt = new LXCOM.LGXPoint();

        let mtx = new LGXMatrix();
        mtx.SetR({ x: 0, y: 0, z: 90 });
        mtx.SetT({ x: 20, y: 10, z: 0 });
        console.log(mtx);
        let p1 = mtx.MultT({ x: 0, y: 2, z: 0 });
        console.log(p1);
        let mtx1 = mtx.Inverse();
        let p2 = mtx1.MultT(p1);
        console.log(p2);
        this.m_pCopyPastService = new copypastesvc.CopyPasteSvc(this.dataManger, this.mainControler, this.m_pRectSelectService);
        this.m_pDragdropsvc = new dragdropsvc.DragDropSvc(this.dataManger);
        this.preMouseDownGraphUnfinish = false;

    }

   

    resizeMap(wid, hgt) {
        this.dataManger.resizeMap(wid, hgt);
        this.displayMng.resizeMap(wid, hgt);
        this.rePaint(1);
    }

    resetMapScreenPos(screenLeft, screenTop, screenRight, screenBottom) {
        this.dataManger.resetMapScreenPos(screenLeft, screenTop, screenRight, screenBottom);
    }

    resetFileMode(editMode) {
        this.editMode = editMode;
        this.mainControler = MainControllerFactory.create(editMode, this.dataManger, this.displayMng, this.m_pRectSelectService);
        if (editMode == "xmind") {
            this.mainControler.autoCreateTrunckThemeGraph(this.painter);
        }
        this.dataManger.resetFileMode(editMode);
    }

    getDataManager() { return this.dataManger; }
    getOperStepService() { return null; }
    getCanvas() { return this.canvas; }
    getPaintMap() { return this.painter; }

    act2Mouse(mosEvent, screenPt) {
        var mapInfo = this.dataManger.getMapViewInfo();
        if (mosEvent.type == LGXEnums.LGXMouseMode.mouseDrag) {
            this.autoTransViewPort(screenPt,mapInfo);
        }

        var p1 = CoordTRFUtil.screen2world(screenPt, mapInfo);
        var tWorldPt = new LXCOM.LGXPoint();
        tWorldPt.x = p1.x;
        tWorldPt.y = p1.y;
        this.m_preMouseScrnPt.clone(screenPt);
        this.m_preMouseWorldPt.clone(tWorldPt);
        // console.log("sx="+screenPt.x +"sy="+screenPt.y);
        // console.log("wx="+tWorldPt.x +"wy="+tWorldPt.y);
        let preUnFinish = false;
        let curentGraph = this.dataManger.getCurentGraph();
        if (curentGraph && curentGraph.getStart() == 1 && curentGraph.getFinish() == 0) {
            preUnFinish = true;
        }

        if (preUnFinish && mosEvent.type == LGXEnums.LGXMouseMode.RMouseDown) {
            this.preMouseDownGraphUnfinish = true;
        }

        let preEditMode = this.dataManger.getEditMode();

        //tWorldPt流转到下级相关工作类后，其值可能会发生改变：如坐标自动吸附功能等
        let resultState = this.mainControler.act2Mouse(this.painter, mosEvent, tWorldPt);
        let curentEditMode = this.dataManger.getEditMode();
        let canRemoveCMDKeyListner = true;
        let svc = eventclassifysvc.EventClassifySvc;
        let evt = svc.getEventParam(this.dataManger, "mouse", resultState, mosEvent, screenPt, tWorldPt);
        if (evt) {
            if (preUnFinish && curentGraph.getFinish() == 1) {
                evt.finishNow = true;
                evt.gid = curentGraph.m_gid;
                evt.uuid = curentGraph.m_rid;
                evt.drawTool = curentGraph.getType();
                evt.eventKind = LGXEnums.LGXEventKind.FinishDraw;
            }
            else if (preEditMode != LGXEnums.EditMode.normal && curentEditMode == LGXEnums.EditMode.normal) {
                evt.eventKind = LGXEnums.LGXEventKind.InSubEditMode;
                let rst = this.parseMouseActResult(resultState);
                if (rst && ((!(resultState.constructor === Object)))) {
                    evt.subEditModeState = rst.subEditModeState;
                    evt.subEditMode = rst.subEditMode;
                    canRemoveCMDKeyListner = false;
                }
            }

            let finishLineOrBusPlotAction = false;
            if (this.preMouseDownGraphUnfinish
                && mosEvent.type == LGXEnums.LGXMouseMode.RMouseUp
                && curentGraph && curentGraph.getFinish() == 1
                && (curentGraph.m_graphType == LGXEnums.LGXGraphType.LineGraph_type
                    || curentGraph.m_graphType == LGXEnums.LGXGraphType.CommBusGraph_type)) {
                finishLineOrBusPlotAction = true;
                this.preMouseDownGraphUnfinish = false;
            }

            if (!finishLineOrBusPlotAction) {
                this.notifyEvents(evt);
            }
        }

        this.setCanvasCursor(mosEvent, screenPt, tWorldPt);
        if (mosEvent.type == LGXEnums.LGXMouseMode.LMouseUp) {
            this.notifySelGraphEvents(tWorldPt);
        }

        if (mosEvent.type == LGXEnums.LGXMouseMode.LMouseDown) {
            if (resultState && resultState.action == "fast_draw" && resultState.tool != 0) {
                let point = resultState.point;
                this.setTool(resultState.tool,resultState.symbolUUID);
                let spt = CoordTRFUtil.world2Screen(point, mapInfo);
                this.actToolDragEvent(spt, "enter");
                this.mainControler.notifyGenerateFastGraph(this.painter);
            }
        }

        if (canRemoveCMDKeyListner) {
            if (mosEvent.type == LGXEnums.LGXMouseMode.LMouseUp
                || mosEvent.type == LGXEnums.LGXMouseMode.RMouseUp
                || mosEvent.type == LGXEnums.LGXMouseMode.MMouseUp) {
                let havaInDrawingGraph = false;
                let curentGraph = this.dataManger.getCurentGraph();
                if (curentGraph && curentGraph.getStart() == 1 && curentGraph.getFinish() == 0) {
                    havaInDrawingGraph = true;
                }
                let editMode = this.dataManger.getEditMode();
                if (!havaInDrawingGraph && editMode == LGXEnums.EditMode.normal) {
                    console.log("remove key event ****************  1");
                    let ele = document.getElementById("cmdinpuArea");
                    //ele.removeEventListener("keydown", window.keyInputFunction);
                    window.autoFocus2CmdInputArea = false;
                }
            }
        }
    }

    act2MouseWheel(delta, mospos, ctrlKeyDown) {
        this.mainControler.act2MouseWheel(this.painter, delta, mospos, ctrlKeyDown);
    }

    onKeyPress(keyevt, mospos) {
        var svc = new shortcutkeysvc.ShortCutKeySvc(this);
        let resultState = svc.onKeyPress(keyevt, mospos);
        if (!resultState) {
            this.mainControler.onKeyPress(this.painter, keyevt, mospos);
        }
    }

    actToMouseHover(mousePoint) {
        var mapInfo = this.dataManger.getMapViewInfo();
        var worldPt = CoordTRFUtil.screen2world(mousePoint, mapInfo);
        this.mainControler.actToMouseHover(this.painter, worldPt);
    }

    setTool(tool,symbolUUID) {
        this.mainControler.setTool(tool,symbolUUID);
        let curentGraph = this.dataManger.getCurentGraph();
        if (funcs.mainObjType(tool) == global.BaseUnitText && curentGraph && curentGraph.getSelect() > 0) {
            this.setCurentGraphTextEdit();
        }
    }

    setCurentGraphTextEdit() {
        var button = 0;
        var shiftDown = 0;
        var altDown = 0;
        var ctrlDown = 0;
        var clientX = 0;
        var clientY = 0;
        var screenX = 0;
        var screenY = 0;
        let type = LGXEnums.LGXMouseMode.LMouseDbClick;

        let mosEvent = { button, type, shiftDown, altDown, ctrlDown, clientX, clientY, screenX, screenY };

        let svc = eventclassifysvc.EventClassifySvc;
        let evt = svc.getEventParam(this.dataManger, "mouse", 0, mosEvent, { x: 0, y: 0 }, { x: 0, y: 0 });
        if (evt) {
            this.notifyEvents(evt);
        }

    }

    setCMDTool(tool) {
        this.mainControler.setTool(tool);
    }

    setMapWorkMode(mode) {
        this.mainControler.setMapWorkMode(mode);
        this.rePaint(1);
    }

    setEditMode(mode) {
        let rst = this.dataManger.setEditMode(mode);
        this.rePaint(1);
        return rst;
    }

    setCurentEditModeRelateValue(value) {
        let mode = this.dataManger.getEditMode();
        this.dataManger.setEditModeRelateValue(mode, value);
    }


    initialSymbol2MemFromStore(symRet) {
        this.initSymbol2Mem(symRet.unitArr, symRet.symbolArr);
    }

    initSymbol2Mem(tSymbolUnitLst, tSymbolDefLst) {
        this.dataManger.initSymbol2Mem(tSymbolUnitLst, tSymbolDefLst);
    }

    getAllSymbolDefLst() {
        return this.dataManger.getAllSymbolDefLst();
    }

    initGraphObjFromStream(jsonData, isStream) {
        console.log("initGraphObjFromStream*************************");
        this.clearData();
        if (!isStream) {
            InitGraphObjSvc.initFrmFile(jsonData, this.dataManger);
        }
        else {
            let tAllSymbolUnitLst = jsonData["exSymUnits"];
            if (tAllSymbolUnitLst && tAllSymbolUnitLst.length > 0) {
                let tAllSymbolUnitObjLst = [];
                for (let i = 0; i < tAllSymbolUnitLst.length; i++) {
                    let unitInfo = tAllSymbolUnitLst[i];
                    var devFullType = unitInfo["type"];
                    var graphInfo = graphdatafactory.GraphDataFactory.create(devFullType);
                    if (graphInfo != null) {
                        graphInfo.fromJson(unitInfo);
                        tAllSymbolUnitObjLst.push(graphInfo);
                    }
                }

                this.initSymbol2Mem(tAllSymbolUnitObjLst, []);
            }
            InitGraphObjSvc.initFrmStream(jsonData, this.dataManger);
            let backColor = this.dataManger.getMapViewInfo().getBackColor();
            let canvasEle = document.getElementById(this.name);
            let str = backColor.toHexString();
            canvasEle.style.backgroundColor = str;
        }
        this.rePaint(1);
    }

    initGraphObjFromInfoList(infoList) {
        console.log("initGraphObjFromStream*************************");
        InitGraphObjSvc.parsingGraph2Mem(infoList, this.dataManger);
        this.rePaint(1);
    }

    clearData() {
        this.dataManger.clearData();
        this.rePaint(1);
    }

    rePaint(kind) {
        this.displayMng.rePaint(this.painter, this.dataManger,kind);
    }

    appendListner(observer) {
        this.m_eventListnerList.push(observer);
    }

    notifyEvents(evt) {
        for (let idx = 0; idx < this.m_eventListnerList.length; idx++) {
            let observer = this.m_eventListnerList[idx];
            observer.actToEvent(evt);
        }
    }

    appendSelGraphListner(observer) {
        if (observer && this.m_selGraphListnerList.indexOf(observer) == -1) {
            this.m_selGraphListnerList.push(observer);
        }
    }

    removeSelGraphListner(observer) {
        let idx = this.m_selGraphListnerList.indexOf(observer);
        if (idx >= 0) {
            this.m_selGraphListnerList.splice(idx, 1);
        }
    }

    notifySelGraphEvents(mousePoint) {
        let list = this.dataManger.getSelGraphs();
        let workMode = this.dataManger.getMapWorkMode();
        if (workMode == LGXEnums.LGXWorkMode.PickPointMode) {
            if (list.length > 0) {
                list.splice(0, list.length);
                list.length = 0;
            }
            let destGraph = this.dataManger.getGraphOnDestPoint(mousePoint);
            if (destGraph) {
                list.push(destGraph);
            }
        }

        let infoList = [];
        list.forEach(p => {
            let info = p.toInfo();
            if (info) {
                infoList.push(info);
            }
        });

        for (let idx = 0; idx < this.m_selGraphListnerList.length; idx++) {
            let observer = this.m_selGraphListnerList[idx];
            observer.notifySelGraph(mousePoint, infoList);
        }
    }


    undo() {
        this.dataManger.m_pOperStepService.backward();
        this.rePaint(1);
    }
    redo() {
        this.dataManger.m_pOperStepService.forward();
        this.rePaint(1);
    }

    copy() {
        this.m_pCopyPastService.copy();
        this.rePaint(1);
    }

    paste() {
        this.m_pCopyPastService.paste(this.m_preMouseScrnPt);
        this.rePaint(1);
    }


    actToolDragEvent(screenPt, dragType) {
        var mapInfo = this.dataManger.getMapViewInfo();
        var p1 = CoordTRFUtil.screen2world(screenPt, mapInfo);
        var tWorldPt = new LXCOM.LGXPoint();
        tWorldPt.x = p1.x;
        tWorldPt.y = p1.y;
        this.m_preMouseScrnPt.clone(screenPt);
        this.m_preMouseWorldPt.clone(tWorldPt);
        let result = this.m_pDragdropsvc.layGraphOnDragEvent(this.painter, tWorldPt, dragType);
        if (dragType == "enter" && result.graph) {
            let curentGraph = result.graph;
            this.dataManger.clearMultiSelDatas();
            this.setMapWorkMode(LGXEnums.LGXWorkMode.ModifyMode);
            this.dataManger.setCurentGraph(curentGraph);
            curentGraph.setSelect(1);
            curentGraph.setSelKind(LGXEnums.LGXModGraphKind.Drag_center);
        }
        if (result.evt) {
            this.notifyEvents(result.evt);
        }
        this.rePaint(1);
    }

    animation() {
        console.log("begin  animate************************");
        let animateManager = this.dataManger.getAnimateManager();
        if (animateManager.animate()) {
            this.rePaint(1);
        }
    }

    setCanvasCursor(mosEvent, screenPt, mousePt) {
        let cursor = "auto";
        let workMode = this.dataManger.getMapWorkMode();
        let subEditMode = this.dataManger.getEditMode();
        if (subEditMode != LGXEnums.EditMode.normal) {
            this.setCursor("auto");
            return;
        }
        switch (workMode) {
            case LGXEnums.LGXWorkMode.DrawGraphMode:
                cursor = "crosshair";
                break;

            case LGXEnums.LGXWorkMode.ModifyMode:
                cursor = this.mainControler.getCursorBySelGraphKind(this.painter,mosEvent,screenPt,mousePt);
                break;

            case LGXEnums.LGXWorkMode.WanderMode:
                cursor = "grab";
                break;

        }

        this.setCursor(cursor);
    }

    getCursorBySelGraphKind(mosEvent, screenPt, mousePt) {
        let cursor = "auto";
        if (this.dataManger.getMapViewInfo().editMode == 'autocad'){
            return cursor;
        }
        let curentSelGraph = this.dataManger.getCurentGraph();
        if (!curentSelGraph) {
            return cursor;
        }

    
        let showCustCursor = false;
        let mapViewInfo = this.dataManger.getMapViewInfo();
        let preShowCustCursor = mapViewInfo.getShowCustCursor();

        let scaling = this.dataManger.getScaling();
        let mapscale = this.dataManger.getMapScale();
        let dragKind = curentSelGraph.calculateSelKind(mousePt, scaling, mapscale);
        switch (dragKind) {
            case LGXEnums.LGXModGraphKind.Drag_leftTop:
                cursor = "nw-resize";//north west
                showCustCursor = true;
                break;

            case LGXEnums.LGXModGraphKind.Drag_rightTop:
                cursor = "ne-resize"; //north east
                showCustCursor = true;
                break;

            case LGXEnums.LGXModGraphKind.Drag_RightBottom:
                cursor = "se-resize"; //south east
                showCustCursor = true;
                break;

            case LGXEnums.LGXModGraphKind.Drag_leftBottom:
                cursor = "sw-resize"; //south west
                showCustCursor = true;
                break;

            case LGXEnums.LGXModGraphKind.Drag_TopMid:
                cursor = "n-resize"; //north east
                showCustCursor = true;
                break;

            case LGXEnums.LGXModGraphKind.Drag_RightMid:
                cursor = "e-resize"; //east
                showCustCursor = true;
                break;

            case LGXEnums.LGXModGraphKind.Drag_BottomMid:
                cursor = "s-resize"; //south
                showCustCursor = true;
                break;

            case LGXEnums.LGXModGraphKind.Drag_LeftMid:
                cursor = "w-resize"; //west
                showCustCursor = true;
                break;

            case LGXEnums.LGXModGraphKind.Drag_center:
                cursor = "move"; //center
                break;

            case LGXEnums.LGXModGraphKind.Drag_rotHand:
                cursor = "pointer";
                break;
        }

        if (showCustCursor) {
            let sizeDragInfo = curentSelGraph.getSizeDragInfo(dragKind);
            mapViewInfo.setCustCursorPt(sizeDragInfo.pt);
            mapViewInfo.setCustCursorVector(sizeDragInfo.vector);
            cursor = "none";
        }
        mapViewInfo.setShowCustCursor(showCustCursor);
        if (preShowCustCursor != showCustCursor){
            this.dataManger.recordRepaintScope(curentSelGraph);
            this.rePaint(0);
        }
        return cursor;
    }
    setCursor(cursor) {
        let canvasArea = document.getElementById(this.name);
        canvasArea.style.cursor = cursor;
    }

    parseMouseActResult(resultState) {
        if (!resultState) {
            return;
        }
        if (!(resultState.constructor === String)) {
            return "";
        }
        let idx = resultState.indexOf("_");
        if (idx == -1) {
            return "";
        }
        let len = resultState.length;
        let subEditModeState = resultState.substring(idx + 1, len);
        let subEditMode = resultState.substring(0, idx);
        return { subEditModeState, subEditMode };
    }

    selectAll() {
        this.mainControler.finishMultiMode();
        SelectAllSvc.selectAll(this.dataManger);
        this.rePaint(1);
    }

    initPatterDefs(base64String) {
        let mng = new fillpatternmanager.FillPatternManager();
        return mng.initDataFromFile(base64String);
    }



    autoTransViewPort(screenPt,mapInfo){
        let winRect = mapInfo.getMapWindowRect();
        const autoGap = 10;
        let width = winRect.width();
        let height = winRect.height();
        if (screenPt.x < autoGap) {
            this.forseTransViewPort(-autoGap, 0, mapInfo);
        }
        else if (screenPt.x > width - autoGap){
            this.forseTransViewPort(autoGap, 0, mapInfo);
        }

        if (screenPt.y < autoGap) {
            this.forseTransViewPort(0, autoGap, mapInfo);
        }
        else if (screenPt.y >height - autoGap) {
            this.forseTransViewPort(0, -autoGap, mapInfo);
        }
    }

    forseTransViewPort(screentx, screenty, mapInfo) {
        let viewPortRect = mapInfo.getViewPort();
        let scaling = mapInfo.getScaling();
        let tx = Math.ceil(screentx / scaling);
        let ty = Math.ceil(screenty / scaling);
        if (tx != 0 || ty != 0) {
            console.log('tx:' + tx + ",ty:" + ty);
            viewPortRect.left += tx;
            viewPortRect.right += tx;
            viewPortRect.top += ty;
            viewPortRect.bottom += ty;

            mapInfo.setViewPort(viewPortRect.left, viewPortRect.top, viewPortRect.right, viewPortRect.bottom);
        }
    }

    exportPng(exportCanvas,width,height,exportBackground){
        let mapInfo = this.dataManger.getMapViewInfo();
        mapInfo.setPaint4PngExport(true);
        let painter = exportCanvas.getContext('2d', { willReadFrequently: true });
        this.displayMng.paint4ExportPng(width,height,exportBackground,painter, this.dataManger);
        mapInfo.setPaint4PngExport(false);
    }
}



export default { MapCanvas }

